<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */
namespace app\service\batch\kuaishou;

use app\enum\CommonEnum;
use app\enum\ConfigEnum;
use app\enum\KuaiShouEnum;
use app\model\KsTargetAgeTaskContentModel;
use app\model\KsTargetAgeTaskLogModel;
use app\model\KsTargetAgeTaskModel;
use app\service\batch\MediaInterface;
use app\service\batch\MediaService;
use app\service\client\AccountService;
use app\service\kuaishou\AdvertiserService;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\facade\Db;
use think\Model;

class TargetAgeService extends MediaService implements MediaInterface
{
    /**
     * @var string 批量改定向年龄锁
     */
    protected const BATCH_KEY = ConfigEnum::CACHE_CONFIG[KuaiShouEnum::BATCH_CONFIG_LOCK_KEY]['target_age'];

    /**
     * @var null|KsTargetAgeTaskModel 任务模型
     */
    private ?KsTargetAgeTaskModel $taskModel;

    /**
     * @var null|KsTargetAgeTaskContentModel 任务内容模型
     */
    private ?KsTargetAgeTaskContentModel $contentModel;

    /**
     * 年龄定向修改.
     *
     * @param KsTargetAgeTaskModel $task 年龄定向任务
     * @return bool
     * @throws DbException
     */
    public function targetAge(KsTargetAgeTaskModel $task): bool
    {
        $this->taskModel = $task;
        // 拉取数据

        if (! $this->getProjectList()) {
            return false;
        }

        return $this->pullTargetAgeFinish();
    }

    /**
     * 拉取完成.
     *
     * @return bool
     * @throws DbException
     */
    private function pullTargetAgeFinish(): bool
    {
        if (! $this->taskModel->getKey()) {
            return self::setError('未知年龄定向模型');
        }

        $num = (new KsTargetAgeTaskContentModel())->where('task_id', $this->taskModel->getKey())->count();
        if (! $num) {
            $this->taskModel->setAttr('status', KsTargetAgeTaskModel::STATUS_SUCCESS);
        }

        $this->taskModel->setAttr('is_pull', KsTargetAgeTaskModel::PULL_SUCCESS);
        return $this->taskModel->save();
    }

    /**
     * 获取数据.
     */
    private function getProjectList(): bool
    {
        if (! $this->taskModel instanceof KsTargetAgeTaskModel || ! $this->taskModel->getKey()) {
            return self::setError('未知年龄定向修改');
        }

        $token = AccountService::getToken(CommonEnum::KS_MEDIA, $this->taskModel->getAttr('advertiser_id'));
        if (! $token) {
            return self::setError('token获取失败');
        }
        $headers = [
            'Access-Token' => $token,
            'Content-Type' => 'application/json',
        ];
        $params['advertiser_id'] = $this->taskModel->getAttr('advertiser_id');
        $params['page_size'] = 100;

        $page = 0;
        while (true) {
            $params['page'] = ++$page;
            $result = AdvertiserService::getHostingProject($headers, $params);
            if ($result === false) {
                return false;
            }
            if (count($result['data']['details']) == 0) {
                return true;
            }
            if (! $this->saveProject($result['data']['details'])) {
                return false;
            }
        }
    }

    /**
     *  保存项目.
     * @param array $list 项目信息队列
     * @return bool
     */
    private function saveProject(array $list = []): bool
    {
        if (! $list) {
            return true;
        }
        foreach ($list as $v) {
            Db::startTrans();
            try {
                // 生成年龄定向记录以及日志
                $this->contentModel = $this->setTargetAgeContent($v);
                if (! $this->contentModel instanceof KsTargetAgeTaskContentModel || ! $this->contentModel->getKey()) {
                    throw new Exception('生成年龄定向记录失败');
                }

                if ($this->contentModel->getAttr('status')) {
                    Db::commit();
                    continue;
                }

                $logModel = $this->setTargetAgeLog();

                if (! $logModel instanceof KsTargetAgeTaskLogModel || ! $logModel->getKey()) {
                    throw new Exception(self::getError(0));
                }
                Db::commit();
            } catch (\Exception $e) {
                Db::rollback();
                return self::setError($e->getMessage());
            }
        }
        return true;
    }

    /**
     * 保存年龄定向修改信息.
     *
     * @param array $data 数据信息
     * @return bool|KsTargetAgeTaskContentModel
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function setTargetAgeContent(array $data = [])
    {
        if (! $this->taskModel instanceof KsTargetAgeTaskModel || ! $this->taskModel->getKey()) {
            return self::setError('未知年龄定向修改');
        }
        $model = (new KsTargetAgeTaskContentModel())->where([
            ['task_id', '=', $this->taskModel->getKey()],
            ['ks_project_id', '=', $data['project_id']],
        ])->find();
        if (! $model instanceof KsTargetAgeTaskContentModel || ! $model->getKey()) {
            $model = new KsTargetAgeTaskContentModel();
            $model->setAttrs([
                'task_id' => $this->taskModel->getKey(),
                'ks_project_id' => $data['project_id'] ?? 0,
                'ks_project_name' => $data['name'] ?? '',
                'ks_project_content' => json_encode($data),
                'target_age' => $this->taskModel->getAttr('content'),
                'status' => KsTargetAgeTaskContentModel::STATUS_WAIT,
            ]);

            $model->save();
        }
        return $model;
    }

    /**
     * 创建年龄定向记录.
     *
     * @return null|array|bool|KsTargetAgeTaskLogModel|mixed|Model
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function setTargetAgeLog()
    {
        if (! $this->contentModel instanceof KsTargetAgeTaskContentModel || ! $this->contentModel->getKey()) {
            return self::setError('未知信息');
        }
        $model = (new KsTargetAgeTaskLogModel())->where([
            ['content_id', '=', $this->contentModel->getKey()],
        ])->find();
        if (! $model instanceof KsTargetAgeTaskLogModel) {
            $model = new KsTargetAgeTaskLogModel();
        }
        if (! $model->getKey()) {
            $model->setAttrs([
                'content_id' => $this->contentModel->getKey(),
            ]);
            if (! $model->save()) {
                return self::setError('生成年龄定向日志失败');
            }
        }
        return $model;
    }
}
